/****************************************************************************
 * Elisa 1.0                                                                *
 *--------------------------------------------------------------------------*
 * Author: Laurent Granvilliers, Vincent Sorin                              *
 * Copyright (c) 2004 Laboratoire d'Informatique de Nantes Atlantique       *
 *--------------------------------------------------------------------------*
 * Elisa is distributed WITHOUT ANY WARRANTY. Read the associated           *
 * COPYRIGHT file for more details.                                         *
 ****************************************************************************/

/**
 * @file elisa_time.h
 * @brief Classes for time management.
 */

#ifndef _ELISA_TIME_H
#define _ELISA_TIME_H

#include <iostream>
#include <iomanip>
#ifndef _WIN32
#include <ctime>
#else
#include <windows.h>
#include <mmsystem.h>
#endif

#include "elisa_defs.h"

NAMESPACE_ELISA

/**
 * @ingroup Utility
 * @class Clock
 * @brief A clock measures the running time of pieces of programs
 */
class Clock
{
public:

	/**
 	 * @brief build a new clock initialized at 0.0
 	 */
	Clock() : m_total(0.0), m_totalMs(0.0)
	{}

	/**
 	 * @brief Copy constructor
 	 */
	Clock(const Clock & c)
		: m_total(c.m_total), m_totalMs(c.m_totalMs), m_lastTop(c.m_lastTop)
	{}

	/**
 	 * @brief Destructor
 	 */
	~Clock()
	{}

	/**
 	 * @brief Initialization of clock
 	 * @post this->get() == 0.0
 	 */
	void reset()
	{
		m_total   = 0.0;
		m_totalMs = 0.0;
	}

	/**
 	 * @brief Starts a new segment of time to be counted by this clock
 	 */
	void start()
	{
#ifndef _WIN32
		m_lastTop = clock();
#else
		m_lastTop = timeGetTime();
#endif
	}

	/**
 	 * @brief Ends the segment of time from the last call of start()
 	 */
	void stop()
	{
#ifndef _WIN32
		clock_t newTop(clock());
#else
		DWORD   newTop(timeGetTime());
#endif
		
		double clocks(static_cast<double>(newTop - m_lastTop));
#ifndef _WIN32
		m_total   += clocks /  CLOCKS_PER_SEC;
		m_totalMs += clocks / (CLOCKS_PER_SEC / 1000);
#else
		m_total   += clocks * 1000;
		m_totalMs += clocks;
#endif
	}

	/**
 	 * @eturn the total accumulated time in seconds
 	 */
	double get() const
	{
		return m_total;
	}


	double getMs() const
	{
		return m_totalMs;
	}

	void print(std::ostream & os) const
	{
		os << m_totalMs;
	}

private:
	/**
 	 * @var last top of time
 	 */
#ifndef _WIN32
	clock_t 
#else
	DWORD
#endif
	m_lastTop;

	/**
 	 * @var accumulated time
 	 */
	double m_total;
	double m_totalMs;

	// Copy protection
	Clock & operator=(const Clock & c);
};

END_NAMESPACE_ELISA


inline std::ostream&
operator<<(std::ostream& os,
		   const elisa::Clock& c)
{
	c.print(os);
	return os;
}

#endif // ELISA_TIME
